// 库
import axios from "axios";
import Vue from "vue";
import { loginOut } from "@/utils/util"
import nprogress from "nprogress";
import "nprogress/nprogress.css";
// 页面
import Loading from "@/components/layout/loading.vue";
// 插件
import {
  tokenReload,
  tokenGet,
  tokenCheck,
  loginReload,
} from "@/utils/tokenManage.js";


/**
 * 添加请求
 */
const addPending = function(config) {
  const { method, url, params, data } = config;
  const id = [method, url, JSON.stringify(params), JSON.stringify(data)].join(
    "&"
  );
  config.cancelToken =
    config.cancelToken ||
    new axios.CancelToken(function excutor(cancel) {
      if (!pendings[id]) {
        pendings[id] = cancel;
      }
    });
  return config;
};

/**
 * 移除请求 - 通过 cancelToken移除请求
 */
const removePending = async function(config) {
  const { method, url, params, data } = config;
  const id = [method, url, JSON.stringify(params), JSON.stringify(data)].join(
    "&"
  );
  const cancel = pendings[id];

  if (cancel && typeof cancel === "function") {
    cancel("多次请求");
    delete pendings[id];
  }
};



// =======  初始化变量 =====
let pendings = {}; // 限流
const errorRequestStatusDeal = {
  500: "网络有点小问题!",
  404: "资源走丢了!",
  401: tokenReload.load,
  403: "权限不足!",
  413: "数据太大!",
};
const successCode = [200, 405, 411, 603, 406]; //不报错的code
// =========================

// 创建 Vue 实例来控制加载动画
const loadingComponent = new Vue(Loading).$mount();
document.body.appendChild(loadingComponent.$el);

// 创建axios实例 - 需要根据 origin来定
const service = axios.create({
  // baseURL: process.env.VUE_APP_BASE_API,
  baseURL: window.location.protocol + "//" + window.location.hostname + ":9999",
  timeout: 100000, // 请求超时时间
});


// request拦截器
/**
 * 限流+续签(24小时过期)
 */
service.interceptors.request.use(
  async (config) => {
    /*
    config 参数
       在请求拦截器中，config 是一个包含请求配置的对象，主要包括以下字段：
        url: 请求的 URL 地址。
        method: 请求方法（如 GET、POST 等）。
        headers: 请求头部。 
        params: 请求的 URL 查询参数。
        data: 请求体（在 POST 或 PUT 请求中使用）。
        timeout: 请求超时设置。
    */
    // console.log(config);
    if (["/login", "/reloadToken"].includes(config.url)) {
      pendings = {};
      return config;
    }
    // console.log(pendings, "--pendings");
    // let url = (config.url + "?").slice(1, (config.url + "?").indexOf("?"));
    // if (pendings[url]) {
    //   return Promise.reject(new Error("多次请求:" + url));
    // }
    // pendings[url] = true;

    removePending(config);
    addPending(config);

    nprogress.start();
    

    let token = tokenGet();
    if (!token) {
      loginReload();
      return;
    }
    // // 验token时限
    // if (tokenCheck() && tokenReload.reloadCheck()) {
    //   await tokenReload.load("request");
    // } else if (!token) {
    //   loginReload();
    //   return;
    // }

    // 获取 token
    config.headers["authorization"] = token;
    // 加密
    // if (config.data) {
    //   config.data = Vue.prototype.$smEncode(config.data);
    // }
    return config;
  },
  (error) => {
    nprogress.set(0.4);
    return Promise.reject(error);
  }
);

// respone拦截器
service.interceptors.response.use(
  async (response) => {
    /*
   response：这是请求成功后的响应对象，包含了服务器返回的数据。你可以在 response 中访问以下主要字段：
    data: 服务器响应的主体数据（通常是你所请求的资源内容）。
    status: HTTP 响应状态码（例如 200、404 等）。
    statusText: HTTP 响应状态的描述文本（例如 "OK" 或 "Not Found"）。
    headers: 响应头，包含了服务器返回的头信息。
    config: 请求的配置对象，包含了发送请求时的参数（如 URL、方法、请求头等）。
    request: 发送请求的原始请求对象。

   error：如果请求失败，error 会包含请求出错的信息，通常是请求失败的原因，例如网络错误、超时错误等。这个 error 对象可能包含以下字段：
    response: 如果服务器返回了错误响应，它会包含与服务器响应相关的信息，类似于 response 对象。
    message: 错误信息，描述了发生的错误。
    config: 请求的配置对象，包含了发送请求时的参数。
   */
    const code = response.data.code;
    if (code != 200) {
      nprogress.done();
      // 异地登录
      if (code == 405) {
        loginOut();
        return response.data;
      }
      if (typeof errorRequestStatusDeal[code] == "string") {
        Vue.prototype.$message.error(response.data.remark || errorRequestStatusDeal[response.code]);
      }
      // else if (tokenReload.reloadCheck()) {
      //   await tokenReload.load("response", response.config);
      // }
      else if (code == 401 || code == 403) {
        loginReload();
        return;
      }
    }
    let url = (response.config.url + "?").slice(1, (response.config.url + "?").indexOf("?"));
    // if (pendings[url]) {
    //   delete pendings[url];
    // }
    removePending(response);
    nprogress.done();
    return response.data;
  },
  (error) => {
    try {
      let url = (error.config?.url + "?").slice(1, (error.config?.url + "?").indexOf("?"));
      if (url && pendings[url]) {
        delete pendings[url];
      }
    } catch (err) { console.log("respone拦截器异常", err) }
    nprogress.done();
    Vue.prototype.$message.error("服务繁忙中!，请稍后再试哦");
    return Promise.reject(error);
  }
);

export default service;
